package cn.ztuo.bitrade.job;

import cn.ztuo.bitrade.Trade.CoinTrader;
import cn.ztuo.bitrade.Trade.CoinTraderFactory;
import cn.ztuo.bitrade.config.AfterServiceStarted;
import cn.ztuo.bitrade.entity.*;
import cn.ztuo.bitrade.runnable.RobotOrderRunnable;
import cn.ztuo.bitrade.service.ContractOrderService;
import cn.ztuo.bitrade.service.ContractPositionService;
import cn.ztuo.bitrade.service.ContractService;
import cn.ztuo.bitrade.util.ContractUtils;
import cn.ztuo.bitrade.util.MessageResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Slf4j
@Component
public class RobotJobBak {

    @Autowired
    private ContractPositionService positionService;
    @Autowired
    private ContractOrderService contractOrderService;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    @Autowired
    private CoinTraderFactory traderFactory;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ContractService contractService;

    private static Map<String,Integer> robotStatusMap =RobotOrderRunnable.robotStatusMap;

    /**
     * 强平
     */
//    @Scheduled(fixedRate = 2000)
    public void forceThrowout() throws Exception {
//        log.info("开始强平......................");
//        contractOrderService.forceThrowout();
        List<ContractPosition> positions = positionService.findAll();
//        log.info("强平结束..........................");
        try {
            positions.stream().filter(a -> (a.getHoldingBond().compareTo(BigDecimal.ZERO) == 1 && a.getContractTotalNum() > 0 && a.getMemberId().longValue() != 0 && a.getMemberId().longValue() != 1)).forEach(a -> {
                synchronized (a.getId().toString().intern()) {
                    a = positionService.getById(a.getId());
                    if(a.getContractOccupyNum()==0){
                        System.out.println(JSON.toJSONString(a));
                    }
                    ContractOrder ask = RobotOrderRunnable.lastPrice.get(a.getSymbol() + "-ask");
                    ContractOrder bid = RobotOrderRunnable.lastPrice.get(a.getSymbol() + "-bid");
                    BigDecimal dealPrice = null;
                    if (ask == null || bid == null) {
                        return;
                    }
                    ContractCoin coin = ContractUtils.getBaseSymbol(a.getSymbol());
                    BigDecimal gainLossRate = null;
                    if (a.getPositionType() == ContractOrderPositionType.RISE) {
                        dealPrice = bid.getPrice();
                        gainLossRate = bid.getPrice().subtract(a.getPositionAvgPrice()).multiply(new BigDecimal(a.getContractTotalNum()).multiply(coin.getMinVolume()))
                                .divide(a.getHoldingBond(), 8, BigDecimal.ROUND_DOWN);
                    }
                    if (a.getPositionType() == ContractOrderPositionType.FALL) {
                        dealPrice = ask.getPrice();
                        gainLossRate = a.getPositionAvgPrice().subtract(ask.getPrice()).multiply(new BigDecimal(a.getContractTotalNum()).multiply(coin.getMinVolume()))
                                .divide(a.getHoldingBond(), 8, BigDecimal.ROUND_DOWN);
                    }

                    if (gainLossRate.compareTo(new BigDecimal(-0.8)) <= 0 || gainLossRate.compareTo(new BigDecimal(1)) >= 0) {
                        ContractPosition position = a;

                        MessageResult mr = null;
                        CoinTrader coinTrader = traderFactory.getTrader(a.getSymbol());
                        List<ContractOrder> needCancelOrders = contractOrderService.findNeedCancelOrders(a.getMemberId(),a.getPositionType());
                        AtomicBoolean success = new AtomicBoolean(contractOrderService.ordersCanceled(needCancelOrders));
                        if (success.get()) {
                            needCancelOrders.stream().filter(b -> b.getStatus() == ContractOrderStatus.TRADING).forEach(contractOrder -> {
                                MessageResult result = null;
                                if (contractOrder.getStatus() == ContractOrderStatus.TRADING) {
                                    result = coinTrader.cancelOrder(contractOrder);
                                }
                                if (result.getCode() != 0) {
                                    success.set(false);
                                    return;
                                }
                            });
                            needCancelOrders = needCancelOrders.stream().filter(b -> b.getStatus() == ContractOrderStatus.WAITING_TRIGGER && b.getType() == ContractOrderType.CHECK_FULL_STOP).collect(Collectors.toList());
                            //远程RPC服务URL,后缀为币种单位
                            JSONObject map = new JSONObject();
                            map.put("symbol", a.getSymbol());
                            map.put("orders", needCancelOrders);
                            String serviceName = "bitrade-contract-market";
                            String url = "http://" + serviceName + "/contract-market/cancelWaitingOrder";
                            mr = restTemplate.postForObject(url, map, MessageResult.class);
                            if (mr.getCode() == 0) {
                                ContractOrder order = new ContractOrder();
                                position = positionService.getByPositionTypeAndSymbolAndMemberId(a.getPositionType(), a.getSymbol(), a.getMemberId());
                                if (gainLossRate.compareTo(new BigDecimal(-0.8)) <= 0) {
                                    order.setStopType(2);
                                }
                                if (gainLossRate.compareTo(new BigDecimal(1)) >= 0) {
                                    order.setStopType(1);
                                }

                                if (position.getPositionType() == ContractOrderPositionType.RISE) {
                                    order.setDirection(ContractOrderDirection.SELL);
                                }
                                if (position.getPositionType() == ContractOrderPositionType.FALL) {
                                    order.setDirection(ContractOrderDirection.BUY);
                                }
//                    order.setForcePrice(dealPrice);
                                order.setPrice(dealPrice);
                                order.setPositionFlag(ContractEnumType.ContractOrderPositionFlag.throwout);
                                order.setPositionOprationType(ContractEnumType.ContractOrderPositionOprationType.force);
                                order.setPositionType(position.getPositionType());
                                order.setNowp(new BigDecimal(position.getContractTotalNum()));
                                order.setSymbol(position.getSymbol());
                                order.setStatus(ContractOrderStatus.NODEAL);
                                order.setBaseSymbol(coin.getBaseSymbol());
                                order.setCoinSymbol(coin.getCoinSymbol());
                                order.setListTime(Calendar.getInstance().getTimeInMillis());
                                order.setAmount(new BigDecimal(position.getContractTotalNum()).multiply(coin.getMinVolume()));
                                order.setMemberId(position.getMemberId());
                                order.setOrderResource(ContractOrderResource.API);
                                order.setType(ContractOrderType.MARKET_PRICE);
                                order.setPositionValue(order.getAmount().multiply(dealPrice));
                                order.setMultiple(new BigDecimal(a.getCurrentMultiple()));

                                order.setStart(position.getUseableBond());
                                BigDecimal fee = ContractUtils.getFee(order.getMemberId(), coin, order.getNowp().multiply(dealPrice).multiply(coin.getMinVolume()));
                                order.setFee(fee);

                                mr = contractOrderService.addOrder(order.getMemberId(), order);
                                log.info("添加挂单成功=====================================================");
                                if (mr.getCode() == 0) {
                                    //市价直接发送到 发送消息至Contract系统
                                    kafkaTemplate.send("contract-order", order.getSymbol(), JSON.toJSONString(order));
                                    messagingTemplate.convertAndSend("/topic/contract/position-force/" + a.getSymbol() + "/" + order.getMemberId(), a);
                                    log.info("结束le ================================");
                                }
                            }
                        }
                    }
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Scheduled(fixedRate = 30*1000)
    public void listenRobotStatus() throws Exception {
        if(AfterServiceStarted.isReday){
            List<ContractCoin> coins = ContractUtils.findBaseSymbols();
            Map<String,Integer> map = RobotOrderRunnable.robotStatusMap;
//        robotStatusMap
            coins.stream().filter(coin->coin.getRobotStatus()==1&&(robotStatusMap.get(coin.getSymbol())==null||robotStatusMap.get(coin.getSymbol())==0)).forEach(coin->{
                map.put(coin.getSymbol(),coin.getRobotStatus());
                RobotOrderRunnable.robotStatusMap=map;
                contractService.robotAddOrder(coin.getSymbol());
            });
        }
    }
}
